using System;
using System.Collections.Generic;
using System.Text;
using System.Security.AccessControl;
using System.Security.Principal;

namespace SBPweb.Security.Authorization
{
	/// <summary>
	/// Class of AccessCheck
	/// </summary>
	public abstract class AccessCheck
	{
		private static Dictionary<Type, AccessCheck> mAccesCheckImplementations = new Dictionary<Type,AccessCheck>();

		static AccessCheck()
		{
			mAccesCheckImplementations[typeof(FileSystemAccessRule)] = new FileSystemAccesCheck();
			mAccesCheckImplementations[typeof(RegistryAccessRule)] = new RegistryAccesCheck();
		}

		/// <summary>
		/// Has right?
		/// </summary>
		/// <param name="user">user</param>
		/// <param name="security">security</param>
		/// <param name="right">right</param>
		/// <returns>true or false</returns>
		public static bool HasRight(MembershipUser user, ObjectSecurity security, Enum right)
		{
			Dictionary<string, IdentityReference> groups = user.AvailableRoles;
			CommonObjectSecurity csec = security as CommonObjectSecurity;
			AuthorizationRuleCollection rc = csec.GetAccessRules(true, true, typeof(NTAccount));
			AuthorizationRule[] ara = new AuthorizationRule[rc.Count];
			rc.CopyTo(ara, 0);
			int allowRights = 0, denyRights = 0;
			foreach (AuthorizationRule ar in rc)
			{
				AccessRule acr = ar as AccessRule;
				if (String.Compare(user.Identity.Name, acr.IdentityReference.Value, true) == 0)
				{
					if (acr.AccessControlType == AccessControlType.Allow)
					{
						allowRights |= mAccesCheckImplementations[acr.GetType()].CombineRights(right, acr);
					}
					else
					{
						denyRights |= mAccesCheckImplementations[acr.GetType()].CombineRights(right, acr);
					}
				}
				if (denyRights != 0)
				{
					return false;
				}
				if (allowRights == Convert.ToInt32(right))
				{
					return true;
				}
			}
			return false;
		}

		/// <summary>
		/// Combine rights
		/// </summary>
		/// <param name="right">right</param>
		/// <param name="acs">access rule</param>
		/// <returns>rights</returns>
		protected abstract int CombineRights(Enum right, AccessRule acs);
	}

	internal class FileSystemAccesCheck : AccessCheck
	{
		protected override int CombineRights(Enum right, AccessRule acs)
		{
			FileSystemRights r = (FileSystemRights)right;
			FileSystemRights ro = (acs as FileSystemAccessRule).FileSystemRights;
			return (int)(r & ro);
		}
	}

	internal class RegistryAccesCheck : AccessCheck
	{
		protected override int CombineRights(Enum right, AccessRule acs)
		{
			RegistryRights r = (RegistryRights)right;
			RegistryRights ro = (acs as RegistryAccessRule).RegistryRights;
			return (int)(r & ro);
		}
	}
}
